package net.lab1024.sa.admin.module.business.pdf.service.impl;

import net.lab1024.sa.admin.module.business.pdf.domain.entity.PdfDocumentContentEntity;
import net.lab1024.sa.admin.module.business.pdf.domain.entity.PdfDocumentEntity;
import net.lab1024.sa.admin.module.business.pdf.service.PdfDocumentContentService;
import net.lab1024.sa.admin.module.business.pdf.service.PdfDocumentService;
import net.lab1024.sa.admin.module.business.pdf.service.PdfParseService;
import net.lab1024.sa.admin.module.business.pdf.util.AdaptiveOcrOptimizer;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;

import jakarta.annotation.Resource;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.concurrent.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.concurrent.ConcurrentHashMap;
import jakarta.annotation.PreDestroy;

import javax.imageio.ImageIO;
import net.lab1024.sa.admin.config.PdfConfig;
import lombok.extern.slf4j.Slf4j;
import java.awt.image.RescaleOp;


/**
 * PDF解析服务实现类 - 混合优化版本
 * 
 * 优化策略：
 * 1. 智能页面预分析：快速识别页面类型，跳过文本页面
 * 2. 异步多线程处理：使用CompletableFuture实现并行处理
 * 3. 简化OCR策略：减少不必要的图像预处理
 * 4. 批量数据库操作：减少数据库写入次数
 * 5. 结果缓存：避免重复处理
 * 6. 内存优化：及时释放资源，控制内存使用
 */
@Slf4j
@Service
public class PdfParseServiceImpl implements PdfParseService {

    @Resource
    private PdfDocumentService pdfDocumentService;
    @Resource
    private PdfDocumentContentService pdfDocumentContentService;
    @Resource
    private PdfConfig pdfConfig;
    @Resource
    private AdaptiveOcrOptimizer adaptiveOcrOptimizer;

    // 优化的线程池配置
    private ExecutorService ocrExecutor;
    private ExecutorService textExtractionExecutor;
    
    // 线程安全的Tesseract实例管理
    private final ThreadLocal<Tesseract> tesseractThreadLocal = new ThreadLocal<>();
    
    // 处理进度跟踪
    private final AtomicInteger processedPages = new AtomicInteger(0);
    private final AtomicInteger successPages = new AtomicInteger(0);
    private final AtomicInteger failedPages = new AtomicInteger(0);
    
    // 结果缓存（避免重复处理）
    private final ConcurrentHashMap<String, String> ocrResultCache = new ConcurrentHashMap<>();
    
    // 批量处理配置
    private static final int BATCH_SIZE = 10; // 批量保存大小
    private static final int MAX_CACHE_SIZE = 1000; // 最大缓存条目数

    @Override
    public Long parseAndSave(MultipartFile file, Long uploadUserId) throws Exception {
        long startTime = System.currentTimeMillis();
        String fileName = file.getOriginalFilename();
        long fileSize = file.getSize() / 1024; // KB
        
        log.info("开始处理PDF文件 - 文件名: {}, 大小: {}KB, 上传用户: {}", fileName, fileSize, uploadUserId);
        
        // 验证文件类型和大小
        validateFile(file);
        
        // 初始化线程池
        initializeThreadPools();
        
        // 重置计数器
        resetCounters();
        
        // 1. 保存原文件到本地
        String filePath = saveUploadedFile(file, fileName);
        
        // 2. 创建文档元信息
        PdfDocumentEntity doc = createDocumentRecord(fileName, filePath, uploadUserId);
        
        // 3. 智能解析PDF内容
        try (PDDocument document = PDDocument.load(new File(filePath))) {
            int pageCount = document.getNumberOfPages();
            doc.setPageCount(pageCount);
            pdfDocumentService.updateById(doc);
            
            log.info("PDF文档加载成功 - 总页数: {}, 开始智能解析...", pageCount);
            
            // 检查OCR配置
            boolean ocrAvailable = isOcrAvailable();
            if (!ocrAvailable) {
                log.warn("OCR功能不可用，将只提取文本内容");
            }
            
            // 3.1 智能页面预分析
            List<PageInfo> pageInfoList = analyzePages(document, ocrAvailable);
            
            // 3.2 异步并行处理页面
            List<PdfDocumentContentEntity> allContentEntities = processPagesAsync(document, doc.getId(), pageInfoList);
            
            // 3.3 批量保存到数据库
            batchSaveContent(allContentEntities);
            
            // 4. 更新文档状态
            doc.setStatus(1); // 解析完成
            pdfDocumentService.updateById(doc);
            
            // 5. 输出性能统计
            long totalTime = System.currentTimeMillis() - startTime;
            outputPerformanceStats(fileName, pageCount, totalTime);
            
        } catch (IOException e) {
            doc.setStatus(-1); // 解析失败
            pdfDocumentService.updateById(doc);
            log.error("PDF解析失败 - 文件名: {}, 错误: {}", fileName, e.getMessage());
            throw e;
        } finally {
            // 清理缓存
            clearCache();
        }
        
        return doc.getId();
    }
    
    /**
     * 验证上传文件
     */
    private void validateFile(MultipartFile file) {
        if (!isValidPdfFile(file)) {
            throw new IllegalArgumentException("不支持的文件类型，请上传PDF文件");
        }
        
        long maxFileSize = pdfConfig.getUploadMaxFileSize() * 1024 * 1024; // 转换为字节
        if (file.getSize() > maxFileSize) {
            throw new IllegalArgumentException("文件大小超过限制，最大允许: " + pdfConfig.getUploadMaxFileSize() + "MB");
        }
    }
    
    /**
     * 初始化线程池
     */
    private void initializeThreadPools() {
        if (ocrExecutor == null) {
            int ocrThreads = Math.max(2, pdfConfig.getOcr().getThreadPoolSize());
            ocrExecutor = new ThreadPoolExecutor(
                ocrThreads, ocrThreads, 60L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(100),
                new ThreadPoolExecutor.CallerRunsPolicy()
            );
            log.debug("初始化OCR线程池，线程数: {}", ocrThreads);
        }
        
        if (textExtractionExecutor == null) {
            int textThreads = Math.max(4, Runtime.getRuntime().availableProcessors());
            textExtractionExecutor = new ThreadPoolExecutor(
                textThreads, textThreads, 60L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(200),
                new ThreadPoolExecutor.CallerRunsPolicy()
            );
            log.debug("初始化文本提取线程池，线程数: {}", textThreads);
        }
    }
    
    /**
     * 重置计数器
     */
    private void resetCounters() {
        processedPages.set(0);
        successPages.set(0);
        failedPages.set(0);
    }
    
    /**
     * 保存上传文件
     */
    private String saveUploadedFile(MultipartFile file, String fileName) throws IOException {
        String uploadDir = System.getProperty("user.dir") + File.separator + "uploads" + File.separator + "pdf" + File.separator;
        File dir = new File(uploadDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        
        String filePath = uploadDir + System.currentTimeMillis() + "_" + fileName;
        File dest = new File(filePath);
        file.transferTo(dest);
        log.debug("文件保存到: {}", filePath);
        
        return filePath;
    }
    
    /**
     * 创建文档记录
     */
    private PdfDocumentEntity createDocumentRecord(String fileName, String filePath, Long uploadUserId) {
        PdfDocumentEntity doc = new PdfDocumentEntity();
        doc.setFileName(fileName);
        doc.setFilePath(filePath);
        doc.setUploadUserId(uploadUserId);
        doc.setUploadTime(LocalDateTime.now());
        doc.setStatus(0);
        pdfDocumentService.save(doc);
        log.debug("创建文档记录，ID: {}", doc.getId());
        return doc;
    }
    
    /**
     * 页面信息类
     */
    private static class PageInfo {
        private final int pageIndex;
        private final boolean isImagePage;
        private final String extractedText;
        private final String pageHash;
        
        public PageInfo(int pageIndex, boolean isImagePage, String extractedText, String pageHash) {
            this.pageIndex = pageIndex;
            this.isImagePage = isImagePage;
            this.extractedText = extractedText;
            this.pageHash = pageHash;
        }
        
        // Getters
        public int getPageIndex() { return pageIndex; }
        public boolean isImagePage() { return isImagePage; }
        public String getExtractedText() { return extractedText; }
        public String getPageHash() { return pageHash; }
    }
    
    /**
     * 智能页面预分析
     */
    private List<PageInfo> analyzePages(PDDocument document, boolean ocrAvailable) throws Exception {
        int pageCount = document.getNumberOfPages();
        List<PageInfo> pageInfoList = new ArrayList<>(pageCount);
        
        log.info("开始智能页面预分析...");
        
        // 使用并行流快速分析所有页面
        List<CompletableFuture<PageInfo>> futures = new ArrayList<>();
        
        for (int i = 0; i < pageCount; i++) {
            final int pageIndex = i;
            CompletableFuture<PageInfo> future = CompletableFuture.supplyAsync(() -> {
                try {
                    return analyzeSinglePage(document, pageIndex, ocrAvailable);
                } catch (Exception e) {
                    log.error("分析页面 {} 失败: {}", pageIndex + 1, e.getMessage());
                    return new PageInfo(pageIndex, false, "", "");
                }
            }, textExtractionExecutor);
            
            futures.add(future);
        }
        
        // 等待所有分析完成
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        allFutures.get(30, TimeUnit.SECONDS); // 30秒超时
        
        // 收集结果
        for (CompletableFuture<PageInfo> future : futures) {
            pageInfoList.add(future.get());
        }
        
        // 统计页面类型
        long imagePages = pageInfoList.stream().filter(PageInfo::isImagePage).count();
        long textPages = pageCount - imagePages;
        
        log.info("页面分析完成 - 总页数: {}, 图片页: {}, 文本页: {}", pageCount, imagePages, textPages);
        
        return pageInfoList;
    }
    
    /**
     * 分析单个页面
     */
    private PageInfo analyzeSinglePage(PDDocument document, int pageIndex, boolean ocrAvailable) throws Exception {
        // 快速提取文本
        PDFTextStripper stripper = new PDFTextStripper();
        stripper.setStartPage(pageIndex + 1);
        stripper.setEndPage(pageIndex + 1);
        String text = stripper.getText(document).trim();
        
        // 判断是否为图片页面
        boolean isImagePage = text.isEmpty() || text.length() < pdfConfig.getOcr().getMinTextLength();
        
        // 生成页面哈希（用于缓存）
        String pageHash = generatePageHash(document, pageIndex);
        
        log.debug("页面 {} 分析完成 - 类型: {}, 文本长度: {}", 
                pageIndex + 1, isImagePage ? "图片页" : "文本页", text.length());
        
        return new PageInfo(pageIndex, isImagePage, text, pageHash);
    }
    
    /**
     * 生成页面哈希（简化版本）
     */
    private String generatePageHash(PDDocument document, int pageIndex) {
        try {
            // 使用页面大小和修改时间作为简单哈希
            return pageIndex + "_" + document.getPage(pageIndex).getMediaBox().getWidth() + 
                   "_" + document.getPage(pageIndex).getMediaBox().getHeight();
        } catch (Exception e) {
            return String.valueOf(pageIndex);
        }
    }
    
    /**
     * 异步并行处理页面
     */
    private List<PdfDocumentContentEntity> processPagesAsync(PDDocument document, Long documentId, List<PageInfo> pageInfoList) throws Exception {
        List<PdfDocumentContentEntity> allContentEntities = new ArrayList<>();
        List<CompletableFuture<PdfDocumentContentEntity>> futures = new ArrayList<>();
        
        log.info("开始异步并行处理页面...");
        
        for (PageInfo pageInfo : pageInfoList) {
            CompletableFuture<PdfDocumentContentEntity> future = CompletableFuture.supplyAsync(() -> {
                try {
                    return processPageOptimized(document, documentId, pageInfo);
                } catch (Exception e) {
                    log.error("处理页面 {} 失败: {}", pageInfo.getPageIndex() + 1, e.getMessage());
                    return createErrorContentEntity(documentId, pageInfo.getPageIndex(), e.getMessage());
                }
            }, pageInfo.isImagePage() ? ocrExecutor : textExtractionExecutor);
            
            futures.add(future);
        }
        
        // 等待所有处理完成，带进度回调
        AtomicInteger completedCount = new AtomicInteger(0);
        for (CompletableFuture<PdfDocumentContentEntity> future : futures) {
            future.thenAccept(entity -> {
                int completed = completedCount.incrementAndGet();
                if (completed % 5 == 0 || completed == pageInfoList.size()) {
                    log.info("页面处理进度: {}/{} ({}%)", 
                            completed, pageInfoList.size(), 
                            String.format("%.1f", completed * 100.0 / pageInfoList.size()));
                }
            });
        }
        
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        allFutures.get(300, TimeUnit.SECONDS); // 5分钟超时
        
        // 收集结果
        for (CompletableFuture<PdfDocumentContentEntity> future : futures) {
            PdfDocumentContentEntity entity = future.get();
            allContentEntities.add(entity);
            
            if (entity.getContent() != null && !entity.getContent().contains("[处理失败")) {
                successPages.incrementAndGet();
            } else {
                failedPages.incrementAndGet();
            }
        }
        
        return allContentEntities;
    }
    
    /**
     * 优化的页面处理
     */
    private PdfDocumentContentEntity processPageOptimized(PDDocument document, Long documentId, PageInfo pageInfo) throws Exception {
        long startTime = System.currentTimeMillis();
        int pageIndex = pageInfo.getPageIndex();
        
        String content;
        int ocrFlag = 0;
        
        try {
            if (pageInfo.isImagePage()) {
                // 图片页面处理
                content = processImagePageOptimized(document, pageIndex, pageInfo.getPageHash());
                ocrFlag = 1;
            } else {
                // 文本页面处理
                content = pageInfo.getExtractedText();
                ocrFlag = 0;
                log.debug("页面 {} 文本页面 - 提取文本长度: {}", pageIndex + 1, content.length());
            }
        } catch (Exception e) {
            log.error("页面 {} 处理失败: {}", pageIndex + 1, e.getMessage());
            content = "[页面处理失败: " + e.getMessage() + "]";
            ocrFlag = 0;
        }
        
        // 创建内容实体
        PdfDocumentContentEntity contentEntity = new PdfDocumentContentEntity();
        contentEntity.setDocumentId(documentId);
        contentEntity.setPageNumber(pageIndex + 1);
        contentEntity.setContent(content);
        contentEntity.setOcrFlag(ocrFlag);
        contentEntity.setCreateTime(LocalDateTime.now());
        
        long processingTime = System.currentTimeMillis() - startTime;
        log.debug("页面 {} 处理完成 - 耗时: {}ms, 类型: {}", 
                pageIndex + 1, processingTime, pageInfo.isImagePage() ? "图片页" : "文本页");
        
        return contentEntity;
    }
    
    /**
     * 优化的图片页面处理
     */
    private String processImagePageOptimized(PDDocument document, int pageIndex, String pageHash) throws Exception {
        // 检查缓存
        String cachedResult = ocrResultCache.get(pageHash);
        if (cachedResult != null) {
            log.debug("页面 {} 使用缓存结果", pageIndex + 1);
            return cachedResult;
        }
        
        // 检查OCR是否可用
        if (!isOcrAvailable()) {
            String result = "[OCR功能不可用：请检查Tesseract安装和语言包配置]";
            ocrResultCache.put(pageHash, result);
            return result;
        }
        
        try {
            // 渲染图片（使用优化的DPI）
            PDFRenderer renderer = new PDFRenderer(document);
            int optimizedDpi =pdfConfig.getOcr().getImageDpi(); // 降低DPI以提高速度
            BufferedImage originalImage = renderer.renderImageWithDPI(pageIndex, optimizedDpi);
            
            if (originalImage == null || originalImage.getWidth() <= 0 || originalImage.getHeight() <= 0) {
                String result = "[OCR识别失败：无法渲染图片]";
                ocrResultCache.put(pageHash, result);
                return result;
            }
            
            log.debug("页面 {} 开始OCR处理 - 图像尺寸: {}x{}, DPI: {}", 
                    pageIndex + 1, originalImage.getWidth(), originalImage.getHeight(), optimizedDpi);
            
            // 简化的图像预处理
            // BufferedImage processedImage = preprocessImageOptimized(originalImage);

            // 自适应优化：根据图像质量自动选择最优策略
            BufferedImage processedImage = optimizeImageForOCR(originalImage);

            
            // 执行OCR
            // String ocrResult = performSimplifiedOCR(processedImage);
            // 使用自适应OCR策略
            String ocrResult=performOptimizedOCR(processedImage);
            
            // 验证OCR结果
            if (ocrResult.isEmpty() || ocrResult.length() < pdfConfig.getOcr().getMinTextLength()) {
                ocrResult = "[OCR识别失败：无法识别图片内容]";
            }
            
            // 缓存结果
            ocrResultCache.put(pageHash, ocrResult);
            
            // 控制缓存大小
            if (ocrResultCache.size() > MAX_CACHE_SIZE) {
                clearCache();
            }
            
            log.debug("页面 {} OCR完成 - 结果长度: {}", pageIndex + 1, ocrResult.length());
            return ocrResult;
            
        } catch (OutOfMemoryError e) {
            log.error("页面 {} OCR处理内存不足: {}", pageIndex + 1, e.getMessage());
            String result = "[OCR识别失败：内存不足，请尝试降低图片DPI或减少并发处理]";
            ocrResultCache.put(pageHash, result);
            return result;
        } catch (Exception e) {
            log.error("页面 {} OCR处理失败: {}", pageIndex + 1, e.getMessage());
            String result = "[OCR识别失败: " + e.getMessage() + "]";
            ocrResultCache.put(pageHash, result);
            return result;
        }
    }
    
    /**
     * 自适应图像预处理，根据图像质量自动优化
     */
    private BufferedImage optimizeImageForOCR(BufferedImage originalImage) {
        try {
            int width = originalImage.getWidth();
            int height = originalImage.getHeight();
            
            log.debug("开始图像预处理 - 原始尺寸: {}x{}", width, height);
            
            // 1. 如果图片太大，先进行缩放以提高速度（但保持较高分辨率）
            int maxDimension = 3000; // 提高最大尺寸以保持图像质量
            if (width > maxDimension || height > maxDimension) {
                double scale = Math.min((double) maxDimension / width, (double) maxDimension / height);
                int newWidth = (int) (width * scale);
                int newHeight = (int) (height * scale);
                
                log.debug("图像缩放 - 缩放比例: {:.2f}, 新尺寸: {}x{}", scale, newWidth, newHeight);
                
                BufferedImage scaledImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
                Graphics2D g2d = scaledImage.createGraphics();
                g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
                g2d.dispose();
                
                originalImage = scaledImage;
                width = newWidth;
                height = newHeight;
            }
            
            // 2. 使用自适应优化器生成优化策略
            AdaptiveOcrOptimizer.OcrOptimizationStrategy strategy = adaptiveOcrOptimizer.generateOptimizationStrategy(originalImage);
            
            log.debug("生成优化策略 - 级别: {}, 对比度增强: {:.2f}x, 锐化: {}, 二值化: {}", 
                    strategy.getPreprocessingLevel(), strategy.getContrastEnhancement(), 
                    strategy.getSharpenLevel(), strategy.isUseBinary() ? "是" : "否");
            
            // 3. 应用优化策略
            BufferedImage optimizedImage = adaptiveOcrOptimizer.applyOptimizationStrategy(originalImage, strategy);
            
            log.debug("图像预处理完成 - 最终尺寸: {}x{}", optimizedImage.getWidth(), optimizedImage.getHeight());
            
            return optimizedImage;
            
        } catch (OutOfMemoryError e) {
            log.warn("图片预处理内存不足，返回原图: {}", e.getMessage());
            return originalImage;
        } catch (Exception e) {
            log.warn("图片预处理失败，返回原图: {}", e.getMessage());
            return originalImage;
        }
    }

    /**
     * 自适应OCR识别策略
     */
    private String performOptimizedOCR(BufferedImage image) throws Exception {
        Tesseract tesseract = getTesseractInstance();
        String bestResult = "";
        String bestStrategy = "无";
        
        try {            
            // 生成自适应优化策略
            AdaptiveOcrOptimizer.OcrOptimizationStrategy strategy = adaptiveOcrOptimizer.generateOptimizationStrategy(image);
            
            // 应用优化策略到Tesseract
            adaptiveOcrOptimizer.applyOptimizationStrategy(tesseract, strategy);
            
            // 策略1: 使用优化后的图像进行OCR
            try {
                BufferedImage optimizedImage = adaptiveOcrOptimizer.applyOptimizationStrategy(image, strategy);
                String result1 = tesseract.doOCR(optimizedImage).trim();
                if (result1 != null && result1.length() > bestResult.length()) {
                    bestResult = result1;
                    bestStrategy = "自适应优化";
                    log.debug("策略1(自适应优化)成功 - 结果长度: {}", result1.length());
                }
            } catch (Exception e) {
                log.debug("策略1(自适应优化)失败: {}", e.getMessage());
            }
            
            // 策略2: 如果策略1结果不够好，尝试原始图像OCR
            if (bestResult.length() < 5) {
                try {
                    // 重置Tesseract参数为默认值
                    tesseract.setTessVariable("tessedit_pageseg_mode", "3");
                    tesseract.setTessVariable("textord_min_linesize", "0.5");
                    tesseract.setTessVariable("textord_heavy_nr", "0");
                    
                    String result2 = tesseract.doOCR(image).trim();
                    if (result2 != null && result2.length() > bestResult.length()) {
                        bestResult = result2;
                        bestStrategy = "原始图像";
                        log.debug("策略2(原始图像)成功 - 结果长度: {}", result2.length());
                    }
                } catch (Exception e) {
                    log.debug("策略2(原始图像)失败: {}", e.getMessage());
                }
            }
            
            // 策略3: 如果前两种策略都不好，尝试灰度图像OCR
            if (bestResult.length() < 5) {
                try {
                    BufferedImage grayImage = convertToGrayscale(image);
                    String result3 = tesseract.doOCR(grayImage).trim();
                    if (result3 != null && result3.length() > bestResult.length()) {
                        bestResult = result3;
                        bestStrategy = "灰度图像";
                        log.debug("策略3(灰度图像)成功 - 结果长度: {}", result3.length());
                    }
                } catch (Exception e) {
                    log.debug("策略3(灰度图像)失败: {}", e.getMessage());
                }
            }
            
            // 记录最终结果
            if (bestResult.length() > 0) {
                log.debug("OCR识别完成 - 最佳策略: {}, 结果长度: {}", bestStrategy, bestResult.length());
            } else {
                log.warn("所有OCR策略均失败，无法识别内容");
            }
            
        } catch (Exception e) {
            log.warn("OCR识别过程异常: {}", e.getMessage());
        }
        
        return bestResult;
    }

    /**
     * 转换为灰度图像
     */
    private BufferedImage convertToGrayscale(BufferedImage image) {
        BufferedImage grayImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        Graphics2D g = grayImage.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return grayImage;
    }


    /**
     * 简化的图像预处理
     */
    private BufferedImage preprocessImageOptimized(BufferedImage originalImage) {
        try {
            int width = originalImage.getWidth();
            int height = originalImage.getHeight();
            
            // 1. 如果图片太大，进行适度缩放
            int maxDimension = 2000; // 降低最大尺寸以提高速度
            if (width > maxDimension || height > maxDimension) {
                double scale = Math.min((double) maxDimension / width, (double) maxDimension / height);
                int newWidth = (int) (width * scale);
                int newHeight = (int) (height * scale);
                
                BufferedImage scaledImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
                Graphics2D g2d = scaledImage.createGraphics();
                g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
                g2d.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
                g2d.dispose();
                
                originalImage = scaledImage;
            }
            
            // 2. 简单的对比度增强
            if (pdfConfig.getOcr().getEnableImagePreprocessing()) {
                float scaleFactor = pdfConfig.getOcr().getContrastEnhancement().floatValue();
                if (scaleFactor > 1.0f) {
                    RescaleOp rescale = new RescaleOp(scaleFactor, 0, null);
                    originalImage = rescale.filter(originalImage, null);
                }
            }
            
            return originalImage;
            
        } catch (OutOfMemoryError e) {
            log.warn("图片预处理内存不足，返回原图: {}", e.getMessage());
            return originalImage;
        } catch (Exception e) {
            log.warn("图片预处理失败，返回原图: {}", e.getMessage());
            return originalImage;
        }
    }
    
    /**
     * 简化的OCR识别
     */
    private String performSimplifiedOCR(BufferedImage image) throws Exception {
        Tesseract tesseract = getTesseractInstance();
        
        // 使用单一策略，避免多次尝试
        tesseract.setLanguage(pdfConfig.getOcr().getDefaultLanguage());
        tesseract.setTessVariable("tessedit_pageseg_mode", "3");
        tesseract.setTessVariable("preserve_interword_spaces", "1");
        
        // 如果启用LSTM引擎
        if (pdfConfig.getOcr().getEnableLstmEngine()) {
            tesseract.setTessVariable("tessedit_ocr_engine_mode", "3");
        }
        
        return tesseract.doOCR(image).trim();
    }
    
    /**
     * 创建错误内容实体
     */
    private PdfDocumentContentEntity createErrorContentEntity(Long documentId, int pageIndex, String errorMessage) {
        PdfDocumentContentEntity entity = new PdfDocumentContentEntity();
        entity.setDocumentId(documentId);
        entity.setPageNumber(pageIndex + 1);
        entity.setContent("[处理失败: " + errorMessage + "]");
        entity.setOcrFlag(0);
        entity.setCreateTime(LocalDateTime.now());
        return entity;
    }
    
    /**
     * 批量保存内容
     */
    private void batchSaveContent(List<PdfDocumentContentEntity> contentEntities) {
        if (contentEntities.isEmpty()) {
            return;
        }
        
        log.info("开始批量保存 {} 个页面内容...", contentEntities.size());
        
        // 分批保存以避免内存问题
        for (int i = 0; i < contentEntities.size(); i += BATCH_SIZE) {
            int endIndex = Math.min(i + BATCH_SIZE, contentEntities.size());
            List<PdfDocumentContentEntity> batch = contentEntities.subList(i, endIndex);
            
            try {
                pdfDocumentContentService.saveBatch(batch);
                log.debug("批量保存完成: {}-{}", i + 1, endIndex);
            } catch (Exception e) {
                log.error("批量保存失败: {}-{}, 错误: {}", i + 1, endIndex, e.getMessage());
                // 尝试逐个保存
                for (PdfDocumentContentEntity entity : batch) {
                    try {
                        pdfDocumentContentService.save(entity);
                    } catch (Exception ex) {
                        log.error("保存页面 {} 失败: {}", entity.getPageNumber(), ex.getMessage());
                    }
                }
            }
        }
        
        log.info("批量保存完成");
    }
    
    /**
     * 输出性能统计
     */
    private void outputPerformanceStats(String fileName, int pageCount, long totalTime) {
        log.info("PDF解析完成 - 文件名: {}, 总页数: {}, 成功: {}, 失败: {}, 处理时间: {}ms, 平均每页: {}ms", 
                fileName, pageCount, successPages.get(), failedPages.get(), totalTime, 
                pageCount > 0 ? totalTime / pageCount : 0);
        
        // 输出性能建议
        if (totalTime > 60000) { // 超过1分钟
            log.info("性能优化建议: 1)降低图片DPI 2)增加线程池大小 3)启用缓存 4)使用SSD存储");
        }
    }
    
    /**
     * 清理缓存
     */
    private void clearCache() {
        ocrResultCache.clear();
        log.debug("OCR结果缓存已清理");
    }
    



    
    /**
     * 单语言OCR识别
     */
    private String performSingleLanguageOCR(File imageFile) throws Exception {
        try {
            // 获取当前线程的Tesseract实例
            Tesseract tesseract = getTesseractInstance();
            
            // 使用配置文件中的默认语言
            String defaultLanguage = pdfConfig.getOcr().getDefaultLanguage();
            log.debug("开始单语言OCR识别，使用语言: {}", defaultLanguage);
            
            tesseract.setLanguage(defaultLanguage);
            
            String result = tesseract.doOCR(imageFile).trim();
            log.debug("单语言OCR识别完成 - 结果长度: {}", result.length());
            
            return result;
        } catch (OutOfMemoryError e) {
            log.error("单语言OCR识别内存不足: {}", e.getMessage());
            // 强制垃圾回收
            System.gc();
            return "";
        } catch (Exception e) {
            log.error("单语言OCR识别失败: {}", e.getMessage());
            return "";
        }
    }
    
    /**
     * 获取线程安全的Tesseract实例
     */
    private Tesseract getTesseractInstance() throws Exception {
        Tesseract tesseract = tesseractThreadLocal.get();
        if (tesseract == null) {
            try {
                log.debug("为线程 {} 创建新的Tesseract实例", Thread.currentThread().getName());
                tesseract = createTesseractInstance();
                tesseractThreadLocal.set(tesseract);
                log.debug("Tesseract实例创建成功");
            } catch (Exception e) {
                log.error("创建Tesseract实例失败: {}", e.getMessage());
                throw e;
            }
        }
        return tesseract;
    }
    
    /**
     * 创建新的Tesseract实例（专门针对中文优化）
     */
    private Tesseract createTesseractInstance() throws Exception {
        Tesseract tesseract = new Tesseract();
        
        // 设置tessdata路径
        String tessdataPath = pdfConfig.getTessdataPath();
        if (tessdataPath == null) {
            throw new Exception("未找到有效的tessdata目录，无法初始化Tesseract。请检查Tesseract安装和语言包配置。");
        }
        tesseract.setDatapath(tessdataPath);
        log.debug("设置Tesseract数据路径: {}", tessdataPath);
        
        // 设置语言包（优先使用中文简体）
        tesseract.setLanguage("chi_sim");
        log.debug("设置Tesseract语言: chi_sim");
        
        // 中文OCR专用优化参数
        // 保留词间空格
        tesseract.setTessVariable("preserve_interword_spaces", "1");
        
        // 使用自动页面分割模式
        tesseract.setTessVariable("tessedit_pageseg_mode", "3"); // 自动页面分割
        
        // 启用LSTM引擎（更准确）
        if (pdfConfig.getOcr().getEnableLstmEngine()) {
            tesseract.setTessVariable("tessedit_ocr_engine_mode", "3"); // 使用LSTM OCR引擎
            log.debug("启用LSTM OCR引擎");
        }
        
        // 中文识别专用参数
        tesseract.setTessVariable("textord_heavy_nr", "0"); // 关闭噪声移除，避免误删中文字符
        tesseract.setTessVariable("textord_min_linesize", "0.5"); // 降低最小行大小要求
        tesseract.setTessVariable("textord_old_baselines", "0"); // 使用新的基线检测
        tesseract.setTessVariable("textord_noise_debug", "0"); // 关闭噪声调试
        
        // 中文识别优化参数
        tesseract.setTessVariable("tessedit_do_invert", "0"); // 不进行图像反转
        tesseract.setTessVariable("debug_file", "/dev/null"); // 关闭调试输出
        tesseract.setTessVariable("tessedit_char_whitelist", ""); // 不限制字符白名单
        tesseract.setTessVariable("tessedit_char_blacklist", ""); // 不限制字符黑名单
        
        // 提高中文识别准确性的参数
        tesseract.setTessVariable("language_model_penalty_non_dict_word", "0.8"); // 降低非词典词惩罚
        tesseract.setTessVariable("language_model_penalty_non_freq_dict_word", "0.8"); // 降低非高频词典词惩罚
        tesseract.setTessVariable("segment_penalty_dict_nonword", "0.8"); // 降低非词分割惩罚
        
        log.debug("Tesseract实例配置完成 - 语言: chi_sim, LSTM引擎: {}", pdfConfig.getOcr().getEnableLstmEngine());
        
        return tesseract;
    }
    
    /**
     * 检查OCR是否可用
     */
    private boolean isOcrAvailable() {
        try {
            String tessdataPath = pdfConfig.getTessdataPath();
            if (tessdataPath == null) {
                log.warn("Tessdata路径未配置");
                return false;
            }
            
            File tessdataDir = new File(tessdataPath);
            if (!tessdataDir.exists() || !tessdataDir.isDirectory()) {
                log.warn("Tessdata目录不存在或不是目录: {}", tessdataPath);
                return false;
            }
            
            // 从配置文件获取需要检查的语言包
            String[] requiredLanguages = pdfConfig.getOcr().getLanguages();
            log.debug("检查语言包: {}", String.join(", ", requiredLanguages));
            
            // 检查是否有配置的语言包
            for (String language : requiredLanguages) {
                File languageFile = new File(tessdataDir, language + ".traineddata");
                if (languageFile.exists()) {
                    long fileSize = languageFile.length() / 1024 / 1024; // MB
                    log.info("找到语言包: {} ({}MB)", language + ".traineddata", fileSize);
                    return true;
                }
            }
            
            log.error("未找到配置的语言包文件");
            log.error("需要的语言包: {}", String.join(", ", requiredLanguages));
            log.error("请检查tessdata目录: {}", tessdataPath);
            return false;
        } catch (Exception e) {
            log.error("检查OCR可用性时出错: {}", e.getMessage());
            return false;
        }
    }
    
    @PreDestroy
    public void cleanup() {
        // 关闭OCR线程池
        if (ocrExecutor != null && !ocrExecutor.isShutdown()) {
            ocrExecutor.shutdown();
            try {
                if (!ocrExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
                    ocrExecutor.shutdownNow();
                }
            } catch (InterruptedException e) {
                ocrExecutor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
        
        // 关闭文本提取线程池
        if (textExtractionExecutor != null && !textExtractionExecutor.isShutdown()) {
            textExtractionExecutor.shutdown();
            try {
                if (!textExtractionExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
                    textExtractionExecutor.shutdownNow();
                }
            } catch (InterruptedException e) {
                textExtractionExecutor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
        
        // 清理缓存
        clearCache();
        
        log.info("PDF解析服务资源清理完成");
    }

    /**
     * 验证是否为有效的PDF文件
     */
    private boolean isValidPdfFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            return false;
        }
        
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null) {
            return false;
        }
        
        // 检查文件扩展名
        String extension = originalFilename.toLowerCase();
        if (!extension.endsWith(".pdf")) {
            return false;
        }
        
        // 检查文件头（PDF文件的魔数）
        try {
            byte[] header = new byte[4];
            file.getInputStream().read(header);
            file.getInputStream().reset(); // 重置流位置
            
            // PDF文件的魔数是 %PDF
            return header[0] == 0x25 && header[1] == 0x50 && header[2] == 0x44 && header[3] == 0x46;
        } catch (Exception e) {
            log.warn("检查PDF文件头失败: {}", e.getMessage());
            // 如果检查失败，只检查扩展名
            return true;
        }
    }
} 